package main

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"strconv"
	"strings"
	"towerdefence/src/pkg/coret"
	"towerdefence/src/pkg/file"
	"towerdefence/src/pkg/logx"
	"unicode"

	"google.golang.org/protobuf/compiler/protogen"
)

var MsgDefMap map[string]int32

func InitMsgDefMap() {
	if MsgDefMap == nil {
		MsgDefMap = make(map[string]int32)
	}
	datas, err := file.ReadConfigFromCSVLines("./proto/def/msgIdDef.csv", 2)
	if err != nil {
		logx.LogError("InitMsgDefMap ReadConfigFromCSVLines is error: %v", err)
		return
	}
	for _, data := range datas {
		msgIdStrs, ok := data.([]string)
		if ok && len(msgIdStrs) == 2 {
			msgkey := msgIdStrs[0]
			msgvalue := coret.Atoi32(msgIdStrs[1])
			MsgDefMap[msgkey] = msgvalue
		}
	}
}

func main() {
	var (
		flags        flag.FlagSet
		plugins      = flags.String("plugins", "", "list of plugins to enable (supported values: grpc)")
		importPrefix = flags.String("import_prefix", "", "prefix to prepend to import paths")
		BaseGen      *protogen.Plugin
	)
	InitMsgDefMap()
	importRewriteFunc := func(importPath protogen.GoImportPath) protogen.GoImportPath {
		switch importPath {
		case "context", "fmt", "math":
			return importPath
		}
		if *importPrefix != "" {
			return protogen.GoImportPath(*importPrefix) + importPath
		}
		return importPath
	}
	protogen.Options{
		ParamFunc:         flags.Set,
		ImportRewriteFunc: importRewriteFunc,
	}.Run(func(gen *protogen.Plugin) error {
		for _, plugin := range strings.Split(*plugins, ",") {
			switch plugin {
			default:
			}
		}
		BaseGen = gen
		return nil
	})

	ses := make([]*Service, 256)
	max := 0
	index := 100
	for _, f := range BaseGen.Files {
		for _, e := range f.Services {
			scomment := string(e.Comments.Leading)
			scomment = strings.ReplaceAll(scomment, "\n", "")
			scomment = strings.ReplaceAll(scomment, " ", "")
			serviceName := e.GoName
			if len(serviceName) > max {
				max = len(serviceName)
			}
			//cmdstr := fmt.Sprintf("%v", e.Desc.Options())
			//cmdstr = strings.ReplaceAll(cmdstr, " ", "")
			//cmdstr = strings.ReplaceAll(cmdstr, "50001:", "")
			//cmd, _ := strconv.Atoi(cmdstr)
			cmd := index
			mes := make([]*Method, 256)
			ser := &Service{name: serviceName, cmd: cmd, methods: mes, comment: scomment}
			if ses[cmd] != nil {
				panic(fmt.Sprintf("CMD 重复 %d", cmd))
			}
			ses[cmd] = ser
			for i, m := range e.Methods {
				lcomment := string(m.Comments.Leading)
				mcomment := lcomment + " " + string(m.Comments.Trailing)
				mcomment = strings.ReplaceAll(mcomment, "\n", "")
				mcomment = strings.ReplaceAll(mcomment, " ", "")
				methodName := m.GoName
				if len(serviceName+"_"+methodName) > max {
					max = len(serviceName + "_" + methodName)
				}
				inPutName := string(m.Desc.Input().Name())
				outPUtName := string(m.Desc.Output().Name())

				act := i
				var typeId int
				if inPutName != "NULL" && outPUtName != "NULL" {
					typeId = 0
				} else if inPutName != "NULL" && outPUtName == "NULL" {
					typeId = 1
				} else if inPutName == "NULL" && outPUtName != "NULL" {
					typeId = 2
				}

				met := &Method{typ: typeId, comment: mcomment, name: methodName, input: inPutName, output: outPUtName, act: act, service: serviceName, cmd: cmd}
				if mes[act] != nil {
					panic(fmt.Sprintf("ACT 重复 %d", act))
				}
				mes[act] = met
			}
			index++
		}
	}
	//wd,_:= os.Getwd()
	//fmt.Println("wd ",wd)
	// if *plugins == "doc" {
	// 	make_doc(ses, "../../doc/")
	// } else {
	makeId(ses, max+5)
	make_handle(ses)
	//make_encode(ses)
	//makeStr(ses)
}

func paserOptions(str string) (string, string) {
	strlist := strings.Split(str, "   ")
	if len(strlist) != 1 {
		return strlist[0], strlist[1]
	}
	strlist = strings.Split(str, "  ")
	if len(strlist) != 1 {
		return strlist[0], strlist[1]
	}
	strlist = strings.Split(str, " ")
	if len(strlist) != 1 {
		return strlist[0], strlist[1]
	}
	return "", ""
}

type Service struct {
	name    string
	cmd     int
	methods []*Method
	comment string
}

type Method struct {
	name    string
	input   string
	output  string
	act     int
	service string
	cmd     int
	comment string
	typ     int
}

func WriteFile(filename string, data []byte) error {
	//fmt.Println(string(data))
	err := os.Remove(filename)
	if err != nil {
		fmt.Println("remove ", err.Error())
	}
	f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
	if err != nil {
		return err
	}
	n, err := f.Write(data)
	if err == nil && n < len(data) {
		err = io.ErrShortWrite
	}
	if err1 := f.Close(); err == nil {
		err = err1
	}
	return err
}

// 驼峰式写法转为下划线写法
func Camel2Case(name string) string {
	buffer := NewBuffer()
	for i, r := range name {
		if unicode.IsUpper(r) {
			if i != 0 {
				buffer.Append('_')
			}
			buffer.Append(unicode.ToLower(r))
		} else {
			buffer.Append(r)
		}
	}
	return buffer.String()
}

// 下划线写法转为驼峰写法
func Case2Camel(name string) string {
	list := strings.Split(name, "_")
	var allstr string
	for _, v := range list {
		allstr = allstr + Ucfirst(LcAll(v))
	}
	return allstr
}

// 首字母大写
func Ucfirst(str string) string {
	for i, v := range str {
		return string(unicode.ToUpper(v)) + str[i+1:]
	}
	return ""
}

// 首字母小写
func Lcfirst(str string) string {
	for i, v := range str {
		return string(unicode.ToLower(v)) + str[i+1:]
	}
	return ""
}

func LcAll(str string) string {
	var s string
	for _, v := range str {
		s = s + string(unicode.ToLower(v))
	}
	return s
}

// 内嵌bytes.Buffer，支持连写
type Buffer struct {
	*bytes.Buffer
}

func NewBuffer() *Buffer {
	return &Buffer{Buffer: new(bytes.Buffer)}
}

func (b *Buffer) Append(i interface{}) *Buffer {
	switch val := i.(type) {
	case int:
		b.append(strconv.Itoa(val))
	case int64:
		b.append(strconv.FormatInt(val, 10))
	case uint:
		b.append(strconv.FormatUint(uint64(val), 10))
	case uint64:
		b.append(strconv.FormatUint(val, 10))
	case string:
		b.append(val)
	case []byte:
		b.Write(val)
	case rune:
		b.WriteRune(val)
	}
	return b
}

func (b *Buffer) append(s string) *Buffer {
	defer func() {
		if err := recover(); err != nil {
			log.Println("*****内存不够了！******")
		}
	}()
	b.WriteString(s)
	return b
}
